package com.school.sports.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.school.sports.entity.Backup;
import com.school.sports.service.BackupService;
import com.school.sports.common.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * 数据备份与恢复控制器
 * 处理数据库备份、恢复、下载等请求
 */
@RestController
@RequestMapping("/api/backup")
@CrossOrigin
public class BackupController {

    private static final Logger logger = LoggerFactory.getLogger(BackupController.class);

    @Autowired
    private BackupService backupService;

    /**
     * 执行数据库备份
     * @param backupName 备份名称
     * @param backupType 备份类型（全量、增量）
     * @return 备份结果
     */
    @PostMapping("/perform")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<Backup> performBackup(
            @RequestParam("backupName") String backupName,
            @RequestParam("backupType") String backupType) {

        logger.info("执行数据库备份请求，备份名称：{}，备份类型：{}", backupName, backupType);

        // 参数校验
        if (backupName == null || backupName.trim().isEmpty()) {
            return Result.fail("备份名称不能为空");
        }
        if (backupType == null || (!"全量".equals(backupType) && !"增量".equals(backupType))) {
            return Result.fail("备份类型必须是'全量'或'增量'");
        }

        try {
            // 获取当前用户ID（实际应该从SecurityContext获取）
            Long currentUserId = getCurrentUserId();

            Backup backup = backupService.performBackup(backupName, backupType, currentUserId);
            logger.info("数据库备份成功，备份ID：{}", backup.getId());

            return Result.success(backup);

        } catch (Exception e) {
            logger.error("数据库备份失败：{}", e.getMessage(), e);
            return Result.fail("备份失败：" + e.getMessage());
        }
    }

    /**
     * 从上传文件恢复数据库
     * @param backupFile 备份文件
     * @return 恢复结果
     */
    @PostMapping("/restore/upload")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<Map<String, Object>> restoreFromUpload(@RequestParam("file") MultipartFile backupFile) {
        logger.info("从上传文件恢复数据库请求，文件名：{}", backupFile.getOriginalFilename());

        // 参数校验
        if (backupFile.isEmpty()) {
            return Result.fail("备份文件不能为空");
        }

        try {
            Long currentUserId = getCurrentUserId();
            Map<String, Object> result = backupService.restoreFromBackup(backupFile, currentUserId);

            if ((Boolean) result.get("success")) {
                logger.info("数据库恢复成功");
                return Result.success(result);
            } else {
                logger.error("数据库恢复失败：{}", result.get("message"));
                return Result.fail((String) result.get("message"));
            }

        } catch (Exception e) {
            logger.error("数据库恢复失败：{}", e.getMessage(), e);
            return Result.fail("恢复失败：" + e.getMessage());
        }
    }

    /**
     * 从备份记录恢复数据库
     * @param backupId 备份记录ID
     * @return 恢复结果
     */
    @PostMapping("/restore/{backupId}")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<Map<String, Object>> restoreFromBackupRecord(@PathVariable("backupId") Long backupId) {
        logger.info("从备份记录恢复数据库请求，备份ID：{}", backupId);

        try {
            Long currentUserId = getCurrentUserId();
            Map<String, Object> result = backupService.restoreFromBackupRecord(backupId, currentUserId);

            if ((Boolean) result.get("success")) {
                logger.info("数据库恢复成功，备份ID：{}", backupId);
                return Result.success(result);
            } else {
                logger.error("数据库恢复失败，备份ID：{}，错误：{}", backupId, result.get("message"));
                return Result.fail((String) result.get("message"));
            }

        } catch (Exception e) {
            logger.error("数据库恢复失败，备份ID：{}，错误：{}", backupId, e.getMessage(), e);
            return Result.fail("恢复失败：" + e.getMessage());
        }
    }

    /**
     * 分页查询备份记录
     * @param currentPage 当前页码
     * @param pageSize 每页显示数量
     * @param backupName 备份名称（可选）
     * @param backupType 备份类型（可选）
     * @param operatorId 操作人ID（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @return 分页结果
     */
    @GetMapping("/page/{currentPage}/{pageSize}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<IPage<Backup>> getBackupPage(
            @PathVariable("currentPage") Integer currentPage,
            @PathVariable("pageSize") Integer pageSize,
            @RequestParam(value = "backupName", required = false) String backupName,
            @RequestParam(value = "backupType", required = false) String backupType,
            @RequestParam(value = "operatorId", required = false) Long operatorId,
            @RequestParam(value = "startTime", required = false) String startTime,
            @RequestParam(value = "endTime", required = false) String endTime) {

        logger.info("分页查询备份记录，当前页码：{}，每页条数：{}", currentPage, pageSize);

        // 参数校验
        if (currentPage == null || currentPage <= 0) {
            currentPage = 1;
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = 10;
        }

        try {
            // 转换时间参数
            LocalDateTime startDateTime = null;
            LocalDateTime endDateTime = null;

            if (startTime != null && !startTime.trim().isEmpty()) {
                startDateTime = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
            if (endTime != null && !endTime.trim().isEmpty()) {
                endDateTime = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }

            IPage<Backup> page = backupService.getBackupPage(
                currentPage, pageSize, backupName, backupType,
                operatorId, startDateTime, endDateTime);

            logger.info("查询备份记录成功，共{}条记录", page.getTotal());
            return Result.success(page);

        } catch (Exception e) {
            logger.error("查询备份记录失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据操作人查询备份记录
     * @param operatorId 操作人ID
     * @return 备份记录列表
     */
    @GetMapping("/operator/{operatorId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<List<Backup>> getBackupsByOperator(@PathVariable("operatorId") Long operatorId) {
        logger.info("根据操作人查询备份记录，操作人ID：{}", operatorId);

        try {
            List<Backup> backups = backupService.getBackupsByOperator(operatorId);
            logger.info("查询到{}条备份记录", backups.size());
            return Result.success(backups);

        } catch (Exception e) {
            logger.error("查询备份记录失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据备份类型查询备份记录
     * @param backupType 备份类型
     * @return 备份记录列表
     */
    @GetMapping("/type/{backupType}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<List<Backup>> getBackupsByType(@PathVariable("backupType") String backupType) {
        logger.info("根据备份类型查询备份记录，备份类型：{}", backupType);

        try {
            List<Backup> backups = backupService.getBackupsByType(backupType);
            logger.info("查询到{}条备份记录", backups.size());
            return Result.success(backups);

        } catch (Exception e) {
            logger.error("查询备份记录失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取最近的备份记录
     * @param limit 限制数量（可选，默认10条）
     * @return 备份记录列表
     */
    @GetMapping("/recent")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<List<Backup>> getRecentBackups(@RequestParam(value = "limit", defaultValue = "10") Integer limit) {
        logger.info("获取最近的备份记录，限制数量：{}", limit);

        try {
            List<Backup> backups = backupService.getRecentBackups(limit);
            logger.info("查询到{}条最近备份记录", backups.size());
            return Result.success(backups);

        } catch (Exception e) {
            logger.error("查询最近备份记录失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 删除备份记录和文件
     * @param backupId 备份记录ID
     * @return 删除结果
     */
    @DeleteMapping("/{backupId}")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<String> deleteBackup(@PathVariable("backupId") Long backupId) {
        logger.info("删除备份请求，备份ID：{}", backupId);

        try {
            boolean success = backupService.deleteBackup(backupId);
            if (success) {
                logger.info("删除备份成功，ID：{}", backupId);
                return Result.success("删除成功");
            } else {
                logger.warn("删除备份失败，ID：{}", backupId);
                return Result.fail("删除失败");
            }

        } catch (Exception e) {
            logger.error("删除备份失败，ID：{}，错误：{}", backupId, e.getMessage(), e);
            return Result.fail("删除失败：" + e.getMessage());
        }
    }

    /**
     * 批量删除备份记录和文件
     * @param backupIds 备份记录ID列表
     * @return 删除结果
     */
    @DeleteMapping("/batch")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<String> batchDeleteBackups(@RequestBody List<Long> backupIds) {
        logger.info("批量删除备份请求，数量：{}", backupIds.size());

        if (backupIds == null || backupIds.isEmpty()) {
            return Result.fail("请选择要删除的备份记录");
        }

        try {
            boolean success = backupService.batchDeleteBackups(backupIds);
            if (success) {
                logger.info("批量删除备份成功，数量：{}", backupIds.size());
                return Result.success("批量删除成功");
            } else {
                logger.warn("批量删除备份部分失败，数量：{}", backupIds.size());
                return Result.fail("部分删除失败");
            }

        } catch (Exception e) {
            logger.error("批量删除备份失败：{}", e.getMessage(), e);
            return Result.fail("批量删除失败：" + e.getMessage());
        }
    }

    /**
     * 下载备份文件
     * @param backupId 备份记录ID
     * @param response HTTP响应对象
     * @return 文件下载响应
     */
    @GetMapping("/download/{backupId}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Resource> downloadBackup(@PathVariable("backupId") Long backupId,
                                                 HttpServletResponse response) {
        logger.info("下载备份文件请求，备份ID：{}", backupId);

        try {
            String filePath = backupService.downloadBackupFile(backupId);
            Path path = Paths.get(filePath);

            if (!Files.exists(path)) {
                logger.error("备份文件不存在，路径：{}", filePath);
                return ResponseEntity.notFound().build();
            }

            Resource resource = new FileSystemResource(path);
            String filename = path.getFileName().toString();

            // URL编码文件名
            String encodedFilename = URLEncoder.encode(filename, "UTF-8");

            logger.info("备份文件下载成功，文件：{}", filename);

            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                            "attachment; filename=\"" + filename + "\"; filename*=UTF-8''" + encodedFilename)
                    .body(resource);

        } catch (Exception e) {
            logger.error("下载备份文件失败，备份ID：{}，错误：{}", backupId, e.getMessage(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 验证备份文件完整性
     * @param backupId 备份记录ID
     * @return 验证结果
     */
    @GetMapping("/validate/{backupId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<Map<String, Object>> validateBackupFile(@PathVariable("backupId") Long backupId) {
        logger.info("验证备份文件请求，备份ID：{}", backupId);

        try {
            Map<String, Object> result = backupService.validateBackupFile(backupId);
            logger.info("备份文件验证完成，备份ID：{}，结果：{}", backupId, result.get("valid"));
            return Result.success(result);

        } catch (Exception e) {
            logger.error("验证备份文件失败，备份ID：{}，错误：{}", backupId, e.getMessage(), e);
            return Result.fail("验证失败：" + e.getMessage());
        }
    }

    /**
     * 获取备份统计信息
     * @return 统计信息
     */
    @GetMapping("/statistics")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<Map<String, Object>> getBackupStatistics() {
        logger.info("获取备份统计信息请求");

        try {
            Map<String, Object> statistics = backupService.getBackupStatistics();
            logger.info("获取备份统计信息成功");
            return Result.success(statistics);

        } catch (Exception e) {
            logger.error("获取备份统计信息失败：{}", e.getMessage(), e);
            return Result.fail("获取统计信息失败：" + e.getMessage());
        }
    }

    /**
     * 创建自动备份任务
     * @param backupName 备份名称
     * @param backupType 备份类型
     * @param scheduleExpression 定时表达式
     * @return 创建结果
     */
    @PostMapping("/schedule")
    @PreAuthorize("hasRole('ADMIN')")
    public Result<Map<String, Object>> createScheduledBackup(
            @RequestParam("backupName") String backupName,
            @RequestParam("backupType") String backupType,
            @RequestParam("scheduleExpression") String scheduleExpression) {

        logger.info("创建定时备份任务请求，备份名称：{}，类型：{}，调度表达式：{}",
            backupName, backupType, scheduleExpression);

        // 参数校验
        if (backupName == null || backupName.trim().isEmpty()) {
            return Result.fail("备份名称不能为空");
        }
        if (backupType == null || (!"全量".equals(backupType) && !"增量".equals(backupType))) {
            return Result.fail("备份类型必须是'全量'或'增量'");
        }
        if (scheduleExpression == null || scheduleExpression.trim().isEmpty()) {
            return Result.fail("调度表达式不能为空");
        }

        try {
            Long currentUserId = getCurrentUserId();
            Map<String, Object> result = backupService.createScheduledBackup(
                backupName, backupType, scheduleExpression, currentUserId);

            logger.info("定时备份任务创建成功");
            return Result.success(result);

        } catch (Exception e) {
            logger.error("创建定时备份任务失败：{}", e.getMessage(), e);
            return Result.fail("创建定时任务失败：" + e.getMessage());
        }
    }

    /**
     * 检查备份文件是否存在
     * @param backupId 备份记录ID
     * @return 检查结果
     */
    @GetMapping("/check/{backupId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<Boolean> checkBackupFileExists(@PathVariable("backupId") Long backupId) {
        logger.info("检查备份文件是否存在，备份ID：{}", backupId);

        try {
            boolean exists = backupService.checkBackupFileExists(backupId);
            logger.info("备份文件存在性检查完成，备份ID：{}，存在：{}", backupId, exists);
            return Result.success(exists);

        } catch (Exception e) {
            logger.error("检查备份文件存在性失败，备份ID：{}，错误：{}", backupId, e.getMessage(), e);
            return Result.fail("检查失败：" + e.getMessage());
        }
    }

    /**
     * 获取备份文件大小
     * @param backupId 备份记录ID
     * @return 文件大小（字节）
     */
    @GetMapping("/size/{backupId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<Long> getBackupFileSize(@PathVariable("backupId") Long backupId) {
        logger.info("获取备份文件大小，备份ID：{}", backupId);

        try {
            Long fileSize = backupService.getBackupFileSize(backupId);
            logger.info("获取备份文件大小成功，备份ID：{}，大小：{}字节", backupId, fileSize);
            return Result.success(fileSize);

        } catch (Exception e) {
            logger.error("获取备份文件大小失败，备份ID：{}，错误：{}", backupId, e.getMessage(), e);
            return Result.fail("获取文件大小失败：" + e.getMessage());
        }
    }

    // ========== 私有辅助方法 ==========

    /**
     * 获取当前用户ID（简化实现）
     * 实际应该从Spring Security的SecurityContext中获取
     */
    private Long getCurrentUserId() {
        // 这里应该实现从SecurityContext获取当前用户信息的逻辑
        // 简化处理，返回管理员ID 1
        return 1L;
    }
}